using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.ComponentModel;

namespace Updater
{
    /// <summary>
    /// 更新帮助类
    /// </summary>
    public class UpdateHelper
    {
        private string _updateFilePath;
        private string _targetExePath;
        private string _targetAppPath;
        private BackgroundWorker _worker;

        /// <summary>
        /// 更新进度事件
        /// </summary>
        public event EventHandler<UpdateProgressEventArgs> UpdateProgress;

        /// <summary>
        /// 更新完成事件
        /// </summary>
        public event EventHandler<UpdateCompletedEventArgs> UpdateCompleted;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="updateFilePath">更新文件路径</param>
        /// <param name="targetExePath">目标可执行文件路径</param>
        /// <param name="targetAppPath">目标应用程序路径</param>
        public UpdateHelper(string updateFilePath, string targetExePath, string targetAppPath)
        {
            _updateFilePath = updateFilePath;
            _targetExePath = targetExePath;
            _targetAppPath = targetAppPath;
        }

        /// <summary>
        /// 开始更新
        /// </summary>
        public void StartUpdate()
        {
            _worker = new BackgroundWorker();
            _worker.WorkerReportsProgress = true;
            _worker.WorkerSupportsCancellation = true;
            _worker.DoWork += Worker_DoWork;
            _worker.ProgressChanged += Worker_ProgressChanged;
            _worker.RunWorkerCompleted += Worker_RunWorkerCompleted;

            _worker.RunWorkerAsync();
        }

        /// <summary>
        /// 取消更新
        /// </summary>
        public void CancelUpdate()
        {
            if (_worker != null && _worker.IsBusy)
            {
                _worker.CancelAsync();
            }
        }

        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                // 报告进度：准备更新
                _worker.ReportProgress(5, "正在准备更新...");

                // 等待目标程序关闭
                _worker.ReportProgress(10, "正在等待目标程序关闭...");
                WaitForProcessToClose(Path.GetFileName(_targetExePath));

                // 报告进度：备份文件
                _worker.ReportProgress(20, "正在备份文件...");
                string backupPath = BackupFile(_targetExePath);

                // 报告进度：开始更新
                _worker.ReportProgress(30, "正在开始更新...");

                // 检查更新文件类型
                string extension = Path.GetExtension(_updateFilePath).ToLower();
                if (extension == ".zip")
                {
                    // 解压ZIP文件
                    _worker.ReportProgress(40, "正在解压更新文件...");
                    ExtractZipFile(_updateFilePath, _targetAppPath);
                    _worker.ReportProgress(80, "解压完成...");
                }
                else
                {
                    // 直接复制文件
                    _worker.ReportProgress(40, "正在复制更新文件...");
                    File.Copy(_updateFilePath, _targetExePath, true);
                    _worker.ReportProgress(80, "复制完成...");
                }

                // 报告进度：验证更新
                _worker.ReportProgress(90, "正在验证更新...");
                if (!File.Exists(_targetExePath))
                {
                    throw new Exception("更新失败：无法找到更新后的程序文件。");
                }

                // 报告进度：完成
                _worker.ReportProgress(100, "更新完成！");

                // 设置结果
                e.Result = new UpdateResult
                {
                    Success = true,
                    Message = "更新成功！",
                    BackupPath = backupPath
                };
            }
            catch (Exception ex)
            {
                // 设置结果
                e.Result = new UpdateResult
                {
                    Success = false,
                    Message = $"更新失败：{ex.Message}"
                };
            }
        }

        private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            OnUpdateProgress(new UpdateProgressEventArgs(e.ProgressPercentage, e.UserState as string));
        }

        private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            OnUpdateCompleted(new UpdateCompletedEventArgs(e.Result as UpdateResult));
        }

        /// <summary>
        /// 等待进程关闭
        /// </summary>
        /// <param name="processName">进程名称</param>
        private void WaitForProcessToClose(string processName)
        {
            Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(processName));
            if (processes.Length > 0)
            {
                foreach (Process process in processes)
                {
                    try
                    {
                        if (!process.HasExited)
                        {
                            process.Kill();
                        }
                    }
                    catch { }
                }

                // 等待进程完全关闭
                for (int i = 0; i < 10; i++)
                {
                    processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(processName));
                    if (processes.Length == 0)
                    {
                        break;
                    }
                    Thread.Sleep(500);
                }
            }
        }

        /// <summary>
        /// 备份文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>备份文件路径</returns>
        private string BackupFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                return null;
            }

            string backupPath = filePath + ".bak";
            File.Copy(filePath, backupPath, true);
            return backupPath;
        }

        /// <summary>
        /// 解压ZIP文件
        /// </summary>
        /// <param name="zipPath">ZIP文件路径</param>
        /// <param name="extractPath">解压路径</param>
        private void ExtractZipFile(string zipPath, string extractPath)
        {
            // 确保解压目录存在
            if (!Directory.Exists(extractPath))
            {
                Directory.CreateDirectory(extractPath);
            }

            // 使用Shell.Application对象解压ZIP文件
            try
            {
                Type shellAppType = Type.GetTypeFromProgID("Shell.Application");
                object shell = Activator.CreateInstance(shellAppType);
                object folder = shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { zipPath });
                object destination = shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { extractPath });
                folder.GetType().InvokeMember("CopyHere", System.Reflection.BindingFlags.InvokeMethod, null, folder, new object[] { destination.GetType().InvokeMember("Items", System.Reflection.BindingFlags.GetProperty, null, destination, null) });
            }
            catch
            {
                // 如果Shell.Application方法失败，尝试使用PowerShell
                ProcessStartInfo psi = new ProcessStartInfo();
                psi.FileName = "powershell.exe";
                psi.Arguments = $"-Command \"Expand-Archive -Path '{zipPath}' -DestinationPath '{extractPath}' -Force\"";
                psi.UseShellExecute = false;
                psi.CreateNoWindow = true;
                psi.WindowStyle = ProcessWindowStyle.Hidden;

                using (Process process = Process.Start(psi))
                {
                    process.WaitForExit();
                    if (process.ExitCode != 0)
                    {
                        throw new Exception("解压ZIP文件失败。");
                    }
                }
            }
        }

        /// <summary>
        /// 触发更新进度事件
        /// </summary>
        /// <param name="e">事件参数</param>
        protected virtual void OnUpdateProgress(UpdateProgressEventArgs e)
        {
            UpdateProgress?.Invoke(this, e);
        }

        /// <summary>
        /// 触发更新完成事件
        /// </summary>
        /// <param name="e">事件参数</param>
        protected virtual void OnUpdateCompleted(UpdateCompletedEventArgs e)
        {
            UpdateCompleted?.Invoke(this, e);
        }
    }

    /// <summary>
    /// 更新进度事件参数
    /// </summary>
    public class UpdateProgressEventArgs : EventArgs
    {
        /// <summary>
        /// 进度百分比
        /// </summary>
        public int ProgressPercentage { get; private set; }

        /// <summary>
        /// 状态消息
        /// </summary>
        public string StatusMessage { get; private set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="progressPercentage">进度百分比</param>
        /// <param name="statusMessage">状态消息</param>
        public UpdateProgressEventArgs(int progressPercentage, string statusMessage)
        {
            ProgressPercentage = progressPercentage;
            StatusMessage = statusMessage;
        }
    }

    /// <summary>
    /// 更新完成事件参数
    /// </summary>
    public class UpdateCompletedEventArgs : EventArgs
    {
        /// <summary>
        /// 更新结果
        /// </summary>
        public UpdateResult Result { get; private set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="result">更新结果</param>
        public UpdateCompletedEventArgs(UpdateResult result)
        {
            Result = result;
        }
    }

    /// <summary>
    /// 更新结果
    /// </summary>
    public class UpdateResult
    {
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool Success { get; set; }

        /// <summary>
        /// 消息
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// 备份文件路径
        /// </summary>
        public string BackupPath { get; set; }
    }
}